package com.cellulam.framework.core.utils;

import com.cellulam.framework.core.context.AppContext;
import com.cellulam.framework.core.model.ExecuteCallback;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class ExecutorUtils {
    private static final int DEFAULT_RETRY_TIMES = 1;

    private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();

    public static final void runAsync(Runnable runnable) {
        runAsync(runnable, null);
    }

    public static final void runAsync(Runnable runnable, ExecuteCallback executeCallback) {
        runAsync(runnable, executeCallback, DEFAULT_RETRY_TIMES);
    }


    public static final void runAsync(Runnable runnable, int retryTimes) {
        runAsync(runnable, null, retryTimes);
    }

    public static final void runAsync(Runnable runnable, ExecuteCallback executeCallback, int retryTimes) {
        Map<String, Object> contextData = AppContext.getContextData();

        THREAD_POOL.execute(() -> {
            AppContext.initContext(contextData);

            int times = 0;
            while (true) {
                try {
                    runnable.run();
                    if (executeCallback != null && executeCallback.getCompletedHandler() != null) {
                        executeCallback.getCompletedHandler().run();
                    }
                    break;
                } catch (Exception e) {
                    log.error("第{}次执行异步任务异常", ++times, e);
                    if (times >= retryTimes) {
                        if (executeCallback != null
                                && executeCallback.getExceptionHandler() != null) {
                            executeCallback.getExceptionHandler().accept(e);
                        }
                        log.error("异步任务执行失败, 共执行{}次，最大执行次数:{}", times, retryTimes);
                        break;
                    }
                    ThreadUtils.sleep(100 * times);
                }
            }
            AppContext.clear();
        });
    }
}
